/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>

// this should be enough
static char buf[65536] = {};
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
static char *code_format =
"#include <stdio.h>\n"
"int main() { "
"  unsigned result = %s; "
"  printf(\"%%u\", result); "
"  return 0; "
"}";

char gen_rand_op() {
	switch (rand()%4) {
    case 0: return '+';
    case 1: return '-';
    case 2: return '*';
    default: return '/';
  }
}

char gen_num() {
	switch (rand()%9) {
    case 0: return '0';
    case 1: return '1';
    case 2: return '2';
    case 3: return '3';
    case 4: return '4';
    case 5: return '5';
    case 6: return '6';
    case 7: return '7';
    case 8: return '8';
    default: return '9';
  }
}

int num = 0;
static void gen_rand_expr() {
//  buf[0] = '\0';
  int choose = rand() % 3;
  //控制最大长度
  if (strlen(buf) > (65536 - 10000))
   choose = 0;
  switch (choose) {
    case 0: buf[num]=gen_num(); num++; buf[num]='u'; num++; break;                              //num <op> num
    case 1: buf[num]='('; num++; gen_rand_expr(); buf[num]=')'; num++; break;                   //(expr)
    default: gen_rand_expr(); buf[num]=gen_rand_op(); num++; gen_rand_expr(); break;            //expr <op> expr
  }
}

void remove_character(char* str, char char_to_remove);

int main(int argc, char *argv[]) {
  int seed = time(0);
  srand(seed);
  int loop = 1;
  if (argc > 1) {
    sscanf(argv[1], "%d", &loop);
  }
  int i;
  for (i = 0; i < loop; i ++) {
  	memset(buf, '\0' ,sizeof(buf)); 
		num=0;
    gen_rand_expr();

    sprintf(code_buf, code_format, buf);

    FILE *fp = fopen("/tmp/.code.c", "w");
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

    int ret = system("gcc -Werror /tmp/.code.c -o /tmp/.expr");
    if (ret != 0) 
    {
      i--;
      continue;
    }

    fp = popen("/tmp/.expr", "r");
    assert(fp != NULL);

    unsigned result;
    int n;
    n = fscanf(fp, "%u", &result);
    pclose(fp);
    if (n != 1){
      i--;
      continue;
    }

    remove_character(buf, 'u');
    printf("%u %s\n", result, buf);
    
    }
  return 0;
}

//remove the 'u'
void remove_character(char* str, char char_to_remove) {
    int read_index = 0, write_index = 0;

    while (str[read_index]) {
        if (str[read_index] != char_to_remove) {
            str[write_index++] = str[read_index];
        }
        read_index++;
    }

    str[write_index] = '\0';
}
